home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / monitory / amyload / device.a < prev    next >
Text File  |  1987-11-15  |  15KB  |  654 lines

  1. *
  2. * Load Device      by Jeff Kelley
  3. *
  4. *   You may give this software to anyone you please.  If you sell it for
  5. *  a profit, you'll just have to live with your conscience.
  6. *
  7. *         (in W.W. Howe V1.0.2 Assembler)
  8. *
  9. LOAD_TASK_PRIORITY  EQU 25
  10. LOAD_PRIORITY        EQU 0
  11. MICROSPERSEC    EQU 1000000
  12. INTERVAL    EQU 5  ; Default time interval length in seconds (sample period)
  13. TICKS        EQU 61 ; Default number of ticks (when samples are taken)  per interval
  14.  
  15.     INCLUDE "exec/types.i"
  16.     INCLUDE "exec/nodes.i"
  17.     INCLUDE "exec/lists.i"
  18.     INCLUDE "exec/ports.i"
  19.     INCLUDE "exec/libraries.i"
  20.     INCLUDE "exec/devices.i"
  21.     INCLUDE "exec/memory.i"
  22.     INCLUDE "exec/io.i"
  23.     INCLUDE "exec/resident.i"
  24.     INCLUDE "exec/tasks.i"
  25.     INCLUDE "exec/errors.i"
  26.     INCLUDE "exec/initializers.i"
  27.     INCLUDE "exec/semaphores.i"
  28.     INCLUDE "exec/execbase.i"
  29.     INCLUDE "hardware/dmabits.i"
  30.     INCLUDE "hardware/custom.i"
  31.     INCLUDE "devices/timer.i"
  32.     INCLUDE "devices/load.i"
  33.     INCLUDE "asmsupp.i"
  34.     INCLUDE "macros.i"
  35.  
  36.     XLIB    OpenDevice
  37.     XLIB    OpenLibrary
  38.     XLIB    AddDevice
  39.     XLIB    AddTask
  40.     XLIB    CloseDevice
  41.     XLIB    Signal
  42.     XLIB    Remove
  43.     XLIB    RemTask
  44.     XLIB    PutMsg
  45.     XLIB    GetMsg
  46.     XLIB    ReplyMsg
  47.     XLIB    Wait
  48.     XLIB    DoIO
  49.     XLIB    AvailMem
  50.     XLIB    FreeMem
  51.     XLIB    Disable
  52.     XLIB    Enable
  53.     XLIB    Forbid
  54.     XLIB    Permit
  55.     XLIB    AllocSignal
  56.     XLIB    InitSemaphore
  57.     XLIB    ObtainSemaphore
  58.     XLIB    ReleaseSemaphore
  59.     XLIB    SetTaskPri
  60.     XREF    _AbsExecBase
  61.     XREF    _custom
  62.  
  63.     SECTION load.device,CODE
  64.  
  65. FirstAddress:
  66.     CLEAR    d0
  67.     rts
  68.  
  69. initDDescrip:
  70.     DC.W    RTC_MATCHWORD
  71.     DC.L    initDDescrip
  72.     DC.L    EndCode
  73.     DC.B    RTF_AUTOINIT
  74.     DC.B    VERSION
  75.     DC.B    NT_DEVICE
  76.     DC.B    LOAD_PRIORITY
  77.     DC.L    LoadName
  78.     DC.L    idString
  79.     DC.L    Init
  80.  
  81. VERSION EQU    1
  82. REVISION EQU    0
  83.  
  84. TimerName   TIMERNAME
  85. LoadName    LOADNAME
  86.  
  87. idString:
  88.     DC.B    'load.device 1.0 (16 October 1987)',13,0
  89.  
  90. Init:
  91.     DC.L    LD_SIZE
  92.     DC.L    funcTable
  93.     DC.L    dataTable
  94.     DC.L    initRoutine
  95.  
  96. funcTable:
  97.     DC.L    Open
  98.     DC.L    Close
  99.     DC.L    Expunge
  100.     DC.L    FirstAddress    ; Null Command (reserved for expansion)
  101.  
  102.     DC.L    BeginIO
  103.     DC.L    AbortIO
  104.  
  105.     DC.L    -1
  106.  
  107. dataTable:
  108.     INITBYTE    LN_TYPE,NT_DEVICE
  109.     INITLONG    LN_NAME,LoadName
  110.     INITBYTE    LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
  111.     INITWORD    LIB_VERSION,VERSION
  112.     INITWORD    LIB_REVISION,REVISION
  113.     INITLONG    LIB_IDSTRING,idString
  114.     DC.L        0
  115.  
  116. *********************************************************************
  117. *
  118. * InitRoutine - initialize the load device structure
  119. *
  120. *      D0 = Device Pointer
  121. *      A0 = Segment List
  122. *      A6 = SysBase
  123. *      If this routine returns non-zero, it will be linked into system
  124. *      device list.
  125.  
  126.  
  127. initRoutine:
  128.     move.l    a5,-(sp)
  129.     movea.l d0,a5        ; get device pointer into safe register
  130.  
  131.     move.l    a0,LD_seglist(a5)
  132.     move.l    a6,LD_sysbase(a5)
  133.  
  134. *   Initialize the Message Port.
  135.     lea    LD_Port(a5),a0
  136.     move.l    #LoadName,LN_NAME(a0)
  137.     move.b    #NT_MSGPORT,LN_TYPE(a0)
  138.     move.b    #PA_IGNORE,MP_FLAGS(a0)
  139.     lea    MP_MSGLIST(a0),a0
  140.     NEWLIST a0
  141.  
  142.     move.w    #INTERVAL,LD_Interval(a5)
  143.     move.w    #TICKS,LD_Ticks(a5)
  144.     move.l    a6,-(sp)
  145.     movea.l a5,a6
  146.     bsr    ComputeDelay
  147.     move.l    (sp)+,a6
  148.  
  149. *   Initialize the semaphore.
  150.     lea    LD_Semaphore(a5),a0
  151.     CALLSYS InitSemaphore        ; InitSemaphore(signalSemaphore)
  152.                     ;            A0
  153.     lea    LD_Semaphore(a5),a0
  154.     CALLSYS ObtainSemaphore     ; ObtainSemaphore(signalSemaphore)
  155.                     ;              A0
  156.  
  157. *   Compute the maximum MEMF_CHIP and MEMF_FAST
  158.     move.l    MemList+LH_HEAD(a6),a0 ; get pointer to first MemHeader node
  159.     DO    addmemory
  160.         move.l  (a0),d1           ; check LN_SUCC
  161.     UNTIL    eq,addmemory
  162.         move.l  MH_UPPER(a0),d0
  163.         sub.l   MH_LOWER(a0),d0
  164.         btst    #MEMB_CHIP,MH_ATTRIBUTES+1(a0)
  165.         IF        ne,chipmemory
  166.         add.l    d0,LD_Max_Chip(a5)
  167.         ELSE    chipmemory
  168.         add.l    d0,LD_Max_Fast(a5)
  169.         FI        chipmemory
  170.         move.l  d1,a0
  171.     OD    addmemory
  172.  
  173. * Create the Load Device task.
  174.     lea    LD_TaskCB(a5),a1
  175.     move.b    #NT_TASK,LN_TYPE(a1)
  176.     move.b    #LOAD_TASK_PRIORITY,LN_PRI(a1)
  177.     move.l    #LoadName,LN_NAME(a1)
  178.     lea    LD_Stack(a5),a0
  179.     move.l    a0,TC_SPLOWER(a1)
  180.     add.l    #LOAD_STACK_SIZE,a0
  181.     move.l    a0,TC_SPUPPER(a1)
  182.     move.l    a0,TC_SPREG(a1)
  183.     lea    TC_MEMENTRY(a1),a0
  184.     NEWLIST a0
  185.     lea    Task_Start,a2
  186.     movea.l #0,a3
  187.     CALLSYS AddTask         ; AddTask(taskCB, initialPC, finalPC)
  188.                     ;          A1      A2     A3
  189.     move.l    a5,d0            ; Return device pointer
  190.  
  191.     move.l    (sp)+,a5        ; restore a5
  192.     rts
  193.  
  194. ***************************************************************************
  195. *
  196. * Open
  197. *
  198. *      A6 = Device
  199. *      A1 = IOB
  200. *      D0 = Unit Number
  201. *      D1 = Flags
  202. *  Return: Set IO_ERROR Field to indicate success/errno
  203.  
  204. Open:
  205.     btst    #LDB_OPEN_EXCL,LD_flags(a6)
  206.     IF    eq,shared_access_ok
  207.         btst    #LDB_OPEN_EXCL,d1
  208.         IF        ne,want_exclusive
  209.         tst.w    LIB_OPENCNT(a6)
  210.         IF    ne,device_in_use
  211.             move.b  LDERR_IN_USE,IO_ERROR(a1)
  212.             rts
  213.         FI    device_in_use
  214.         bset    #LDB_OPEN_EXCL,LD_flags(a6)
  215.         FI        want_exclusive
  216.         addq.w  #1,LIB_OPENCNT(a6)
  217.         cmpi.w  #1,LIB_OPENCNT(a6)
  218.         IF        eq,startup
  219.         lea    LD_Semaphore(a6),a0
  220.         LINKSYS ReleaseSemaphore    ; ReleaseSemaphore(signalSemaphore)
  221.                         ;               A0
  222.         FI        startup
  223.         move.w  LD_Interval(a6),LV_INTERVAL(a1)
  224.         move.w  LD_Ticks(a6),LV_TICKS(a1)
  225.         move.b  LD_TaskCB+LN_PRI(a6),LV_PRI(a1)
  226.         clr.b   IO_ERROR(a1)
  227.     ELSE    shared_access_ok
  228.         move.b  #LDERR_ACCESS_DENIED, IO_ERROR(a1)
  229.     FI    shared_access_ok
  230.     rts
  231.  
  232. ***************************************************************************
  233. *
  234. * Close
  235. *
  236. *      A6 = Device
  237. *      A1 = IOB
  238. *  Return: If the device is no longer open and a delayed expunge is pending,
  239. *       do the expunge and return the segment list.    Else return NULL.
  240.  
  241. Close:
  242.     clr.l    IO_DEVICE(a1)
  243.     subq.w    #1,LIB_OPENCNT(a6)
  244.     IF    eq,do_close
  245.         lea     LD_Semaphore(a6),a0
  246.         LINKSYS ObtainSemaphore    ; ObtainSemaphore(signalSemaphore)
  247.                     ;          A0
  248.         bclr    #LDB_OPEN_EXCL,LD_flags(a6)
  249.         btst    #LIBB_DELEXP,LIB_FLAGS(a6)
  250.         IF        ne,go_expunge
  251.         bra.s    Expunge
  252.         FI        go_expunge
  253.     FI    do_close
  254.     CLEAR    d0
  255.     rts
  256.  
  257. ****************************************************************************
  258. *
  259. * Expunge
  260. *
  261. *      A6 = Device
  262. *  Return: If the device is no longer open return seg list. Else set
  263. *       delayed Expunge flag and return NULL.
  264. Expunge:
  265.  
  266.     move.l    a5,-(sp)
  267.     move.l    a6,a5
  268.     move.l    LD_sysbase(a5),a6
  269. *     Check to see if anyone has us open
  270.  
  271.     tst.w    LIB_OPENCNT(a5)
  272.     IF    ne,still_open
  273.  
  274. *    It is still open, set delayed Expunge flag
  275.  
  276.         bset    #LIBB_DELEXP,LIB_FLAGS(a5)
  277.         CLEAR   d0
  278.  
  279.     ELSE    still_open
  280.  
  281. *    Go ahead and get rid of us.
  282.  
  283.         move.l  LD_seglist(a5),-(a7)    ; We need to return this value
  284.  
  285. *    Unlink from device list.
  286.         movea.l a5,a1
  287.         CALLSYS Remove            ; Remove(node)
  288.                         ;         A1
  289. *    Remove the load.device task
  290.         lea     LD_TaskCB(a5),a1
  291.         CALLSYS RemTask            ; RemTask(taskCB)
  292.                         ;          A1
  293. *    Close the timer device.
  294.         lea     LD_TimerRequest(a5),a1
  295.         CALLSYS CloseDevice         ; CloseDevice(ioRequest)
  296.                         ;          A1
  297. *    Free the memory allocated to the library.
  298.         CLEAR   d0
  299.         movea.l a5,a1
  300.         move.w  LIB_NEGSIZE(a5),d0
  301.         sub.w   d0,a1
  302.         add.w   LIB_POSSIZE(a5),d0
  303.         CALLSYS FreeMem            ; FreeMem(memBlock, byteSize)
  304.                         ;          A1    D0
  305.         move.l  (a7)+,d0
  306.     FI  still_open
  307.     move.l a5,a6
  308.     move.l (sp)+,a5
  309.     rts
  310.  
  311. *************************************************************************
  312. *
  313. * BeginIO
  314. *
  315. *      A6 = Device
  316. *      A1 = IOB
  317.  
  318. BeginIO:
  319.     clr.b    IO_ERROR(a1)
  320.     move.w    IO_COMMAND(a1),d0
  321.     asl.w    #2,d0            ; Compute displacement
  322.     lea    cmdtable(pc),a0
  323.     add.w    d0,a0
  324. *    cmpa.l    #cmdtable_end,a0    ; Check to make sure it's in range.
  325. * (Assembler doesn't handle it right, so...)
  326.     dc.w    $B1FC
  327.     dc.l    cmdtable_end
  328.     bcs.s    cmd_ok            ; branch if a0 < #cmdtable_end
  329.     lea    cmdtable(pc),a0     ; Get the address of CMD_INVALID
  330. cmd_ok:
  331.     movea.l (a0),a0
  332.     jmp    (a0)
  333.  
  334. ****************************************************************************
  335. *
  336. * AbortIO
  337. *
  338. *      A6 = Device
  339. *      A1 = IOB
  340. AbortIO:
  341. * Scan list for the IOB node
  342.     LINKSYS Forbid
  343.     move.l    LD_Port+MP_MSGLIST+LH_HEAD(a6),d1
  344.     DO    scanlist
  345.         movea.l d1,a0
  346.         move.l  (a0),d1          ; get LN_SUCC
  347.         beq.s   not_found
  348.         cmpa.l  a0,a1
  349.     WHILE    ne,scanlist
  350.     OD    scanlist
  351.  
  352.     move.l    a1,d1
  353.     REMOVE    a1            ; Remove the IOB node from the list.
  354.     LINKSYS Permit
  355.     movea.l d1,a1
  356.     move.b    #IOERR_ABORTED,IO_ERROR(a1)
  357.     rts
  358. not_found:
  359.     LINKSYS Permit
  360.     clr.b  IO_ERROR(a1)        ; Indicate an error occurred.
  361.     rts
  362.  
  363. cmdtable:
  364.     DC.L    Invalid
  365.     DC.L    Reset
  366.     DC.L    Read
  367.     DC.L    Write
  368.     DC.L    Update
  369.     DC.L    Clear
  370.     DC.L    Stop
  371.     DC.L    Start
  372.     DC.L    Flush
  373.     DC.L    Set
  374. cmdtable_end:
  375.  
  376. *******************************************************************
  377. *
  378. *    A6 = device
  379. *    A1 = IOB
  380.  
  381. Write:
  382. Update:
  383. Clear:
  384. Invalid:
  385.     move.b    #IOERR_NOCMD,IO_ERROR(a1)
  386.     rts
  387.  
  388. Read:
  389. * If IO_QUICK is set, get the most recent values and return, do not reply.
  390. * Otherwise, queue the IO request. Return.  Reply will come later.
  391.  
  392.     btst    #IOB_QUICK,IO_FLAGS(a1)
  393.     IF    ne,do_quickio
  394.         move.l  LD_CPU(a6),LV_CPU(a1)
  395.         move.l  LD_BLITTER(a6),LV_CPU(a1)
  396.         move.l  LD_CHIP(a6),LV_CHIP(a1)
  397.         move.l  LD_FAST(a6),LV_FAST(a1)
  398.     ELSE    do_quickio
  399.         lea     LD_Port(a6),a0
  400.         LINKSYS PutMsg        ; PutMsg(msgPort, message)
  401.     FI    do_quickio        ;     A0      A1
  402.     rts
  403. Stop:
  404.     LINKSYS Forbid
  405.     tst.b    LD_stop_count(a6)
  406.     IF    eq,stop_load_task
  407.         lea     LD_Semaphore(a6),a0
  408.         LINKSYS ObtainSemaphore
  409.     FI    stop_load_task
  410.     addq.b    #1,LD_stop_count(a6)
  411.     LINKSYS Permit
  412.     rts
  413. Start:
  414.     tst.b    LD_stop_count(a6)
  415.     IF    eq,not_stopped
  416.         move.b  #LDERR_NOT_STOPPED,IO_ERROR(a1)
  417.     ELSE    not_stopped
  418.         LINKSYS Forbid
  419.         subq.b  #1,LD_stop_count(a6)
  420.         IF        eq,start_load_task
  421.         lea    LD_Semaphore(a6),a0
  422.         LINKSYS ReleaseSemaphore
  423.         FI        start_load_task
  424.         LINKSYS Permit
  425.     FI    not_stopped
  426.     rts
  427.  
  428. * Reply to all pending requests, setting IOERR_ABORTED.
  429. Flush:
  430.     LINKSYS Forbid
  431.     DO    flushrequests
  432.         lea     LD_Port(a6),a0
  433.         LINKSYS GetMsg        ; message = GetMsg(msgPort)
  434.         tst.l   d0            ; D0           A0
  435.     UNTIL     eq,flushrequests
  436.         movea.l d0,a1
  437.         move.b  #IOERR_ABORTED,IO_ERROR(a1)
  438.         LINKSYS ReplyMsg        ; ReplyMsg(message)
  439.                     ;           A1
  440.     OD    flushrequests
  441.     LINKSYS Permit
  442.     rts
  443.  
  444. Reset:
  445. ;   Set default values.
  446.     move.w    #INTERVAL,LV_INTERVAL(a1)
  447.     move.w    #TICKS,LV_TICKS(a1)
  448.     move.b    #LOAD_TASK_PRIORITY,LV_PRI(a1)
  449. ;   FALLTHROUGH into the Set command
  450.  
  451. Set:
  452.     move.l    a1,-(sp)
  453.     lea    LD_Semaphore(a6),a0
  454.     LINKSYS ObtainSemaphore     ; ObtainSemaphore(signalSemaphore)
  455.                     ;              A0
  456.     move.l    (sp)+,a1
  457.     move.w    LV_INTERVAL(a1),LD_Interval(a6)
  458.     move.w    LV_TICKS(a1),LD_Ticks(a6)
  459.     bsr.s    ComputeDelay
  460.     move.b    LV_PRI(a1),d0
  461.     lea    LD_TaskCB(a6),a1
  462.     LINKSYS SetTaskPri        ; oldPriority = SetTaskPri(taskCB, newpriority)
  463.                     ; D0.b               A1      D0.b
  464.     lea    LD_Semaphore(a6),a0
  465.     LINKSYS ReleaseSemaphore    ; ReleaseSemaphore(signalSemaphore)
  466.                     ;               A0
  467.     rts
  468.  
  469. ***************************************************************************
  470. *
  471. * ComputeDelay subroutine - From the LD_Interval and LD_Ticks, compute the
  472. *                delay in seconds and microseconds between ticks.
  473. *
  474. *   Input:   A6 - Load Device
  475. *         LD_Interval(a6) - Interval in seconds
  476. *         LD_Ticks(a6)    - Number of Ticks per Interval
  477. *
  478. *   Output:  LD_secs(a6)     - delay in seconds
  479. *         LD_micro(a6)    - delay in microseconds
  480. *
  481. *   Destroys: a0,d0,d1
  482. *
  483.  
  484. ComputeDelay:
  485.     move.l    d2,-(a7)
  486.     CLEAR    d1
  487.     move.w    LD_Interval(a6),d1        ; INTERVAL in seconds
  488.     move.w    LD_Ticks(a6),d2         ; number of TICKS per INTERVAL
  489.     mulu    #20,d1                ; multiply d0 by a MICROSPERSEC
  490.     mulu    #50000,d1            ; (in 2 steps, since can't mult by >65536)
  491.  
  492. *    d1.l = d1.l / d2.w
  493.  
  494.     movea.w d1,a0
  495.     clr.w    d1
  496.     swap    d1
  497.     divu    d2,d1
  498.     move.l    d1,d0
  499.     swap    d1
  500.     move.w    a0,d0
  501.     divu    d2,d0
  502.     move.w    d0,d1
  503.  
  504. *    LD_secs  = d1.l / MICROSPERSEC
  505. *    LD_micro = d1.l % MICROSPERSEC
  506.  
  507.     clr.l    LD_secs(a6)
  508.     DO    incrsecs
  509.         cmp.l #MICROSPERSEC,d1
  510.     WHILE    ge,incrsecs
  511.         sub.l #MICROSPERSEC,d1
  512.         addi.l #1,LD_secs(a6)
  513.     OD    incrsecs
  514.     move.l    d1,LD_micro(a6)
  515.  
  516.     move.l    (a7)+,d2
  517.     rts
  518.  
  519. ********************************************************************
  520. *
  521. * Load Task
  522. *
  523. * Register Usage:   a6 : SysBase
  524. *            a2 : Semaphore
  525. *            a3 : TimerPort
  526. *            a4 : TimerMessage
  527. *            a5 : LoadDevice
  528. *
  529. *            d2 : Current Tick count
  530. *            d3 : Ready Queue counter
  531. *            d4 : Blitter Use counter
  532. *            d5 : Chip Mem available
  533. *            d6 : Fast Mem available
  534. *            d7 : <Free Safety>
  535.  
  536. *  To get a pointer to the Load Device structure, use a7 as a base.
  537. *  It points to the last longword of the stack (which contains the
  538. *  address of a cleanup routine).
  539. *                                    a7
  540. *  |    <---------- LD_Stack ----------->   | <- LOAD_STACK_SIZE - 4 ->  |
  541. *  |----------------------------------------------------------------------|
  542. *  | Load Device   | TimerRequest | etc.    | Stack              |
  543. *  |----------------------------------------------------------------------|
  544.  
  545. Task_Start:
  546.     move.l    _AbsExecBase,a6
  547.     lea    -LD_Stack-LOAD_STACK_SIZE+4(a7),a5   ; Get Load Device ptr
  548.  
  549.     lea    LD_Semaphore(a5),a2
  550.  
  551. *   Initialize the Timer Port.
  552.     lea    LD_TimerPort(a5),a3
  553.     move.b    #NT_MSGPORT,LN_TYPE(a3)
  554.     move.b    #PA_SIGNAL,MP_FLAGS(a3)
  555.     moveq.l #-1,d0
  556.     CALLSYS AllocSignal        ; signalNum = AllocSignal(signalNum)
  557.     move.b    d0,MP_SIGBIT(a3)    ; D0              D0
  558.     lea    LD_TaskCB(a5),a0
  559.     move.l    a0,MP_SIGTASK(a3)
  560.     lea    MP_MSGLIST(a3),a0
  561.     NEWLIST a0
  562.  
  563. *   Initialize the timer IO request
  564.     lea    LD_TimerRequest(a5),a4
  565.     move.b    #NT_MESSAGE,LN_TYPE(a4)
  566.     move.l    a3,MN_REPLYPORT(a4)
  567.     move.w    #IOTV_SIZE,MN_LENGTH(a4)
  568.  
  569. *   Open the timer.device
  570.     lea    TimerName,a0
  571.     movea.l a4,a1
  572.     moveq.l #UNIT_VBLANK,d0
  573.     CLEAR    d1
  574.     CALLSYS OpenDevice    ; error = OpenDevice(Name,Unit,ioRequest,flags)
  575.                   ; D0           A0    D0   A1        D1
  576.     DO    mainloop
  577.         move.l  a2,a0
  578.         CALLSYS ObtainSemaphore    ; ObtainSemaphore(signalSemaphore)
  579.         move.w  LD_Ticks(a5),d2    ;          A0
  580.         moveq.l #0,d3
  581.         moveq.l #0,d4
  582.  
  583. *        'tickloop' is done once for each 'tick'.
  584.         DO        tickloop
  585.         move.w    #TR_ADDREQUEST,IO_COMMAND(a4)
  586.         move.l    LD_secs(a5),IOTV_TIME+TV_SECS(a4)
  587.         move.l    LD_micro(a5),IOTV_TIME+TV_MICRO(a4)
  588.         movea.l a4,a1
  589.         CALLSYS DoIO            ; error = DoIO(ioRequest)
  590.                         ; D0       A1
  591. *        Compute System Statistics:
  592.  
  593. *        Measure length of ready queue
  594. *        Note: LoadTask is not in this queue, since we are running.
  595.  
  596.         CALLSYS Disable
  597.         movea.l TaskReady+LH_HEAD(a6),a1  ; Get Pointer to first
  598.         DO    readycount          ; node into a1.
  599.             move.l  (a1),d0          ; Look ahead.
  600.         UNTIL    eq,readycount
  601.             addq.l  #1,d3
  602.             movea.l d0,a1
  603.         OD    readycount
  604.         CALLSYS Enable
  605.  
  606. *        Check if blitter busy
  607.  
  608. *        move.w    _custom+dmaconr,d0      ; Assembler can't handle this...
  609.         move.w    $DFF002,d0
  610.         btst    #DMAB_BLTDONE,d0
  611.         IF  ne,busy
  612.             addq.l  #1,d4
  613.         FI  busy
  614.  
  615.         subq.w    #1,d2         ; Decrement tick count
  616.         UNTIL   eq,tickloop
  617.         OD        tickloop
  618.  
  619. *        Compute available memory
  620.  
  621.         move.l  #MEMF_CHIP,d1
  622.         CALLSYS AvailMem            ; size = AvailMem(requirements)
  623.         move.l  LD_Max_Chip(a5),d5        ; D0          D1
  624.         sub.l   d0,d5
  625.  
  626.         move.l  #MEMF_FAST,d1
  627.         CALLSYS AvailMem            ; size = AvailMem(requirements)
  628.         move.l  LD_Max_Fast(a5),d6        ; D0          D1
  629.         sub.l   d0,d6
  630.         move.l  d3,LD_CPU(a5)
  631.         move.l  d4,LD_BLITTER(a5)
  632.         move.l  d5,LD_CHIP(a5)
  633.         move.l  d6,LD_FAST(a5)
  634.  
  635.         DO        reply
  636.         lea    LD_Port(a5),a0
  637.         CALLSYS GetMsg            ; message = GetMsg(msgPort)
  638.         tst.l    d0            ; D0           A0
  639.         UNTIL    eq,reply
  640.         movea.l d0,a1
  641.         move.l    d3,LV_CPU(a1)
  642.         move.l    d4,LV_BLITTER(a1)
  643.         move.l    d5,LV_CHIP(a1)
  644.         move.l    d6,LV_FAST(a1)
  645.         CALLSYS ReplyMsg        ; ReplyMsg(message)
  646.         OD        reply            ;           A1
  647.  
  648.         lea     LD_Semaphore(a5),a0
  649.         CALLSYS ReleaseSemaphore        ; ReleaseSemaphore(signalSemaphore)
  650.     ODL    mainloop            ;               A0
  651.  
  652. EndCode:
  653.     END
  654.